﻿using Nature.Core.Exceptions;
using StructureMap;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Nature.Core.Boot
{
    public class BootManager
    {
        /// <summary>
        ///     需要启动的Boot对象
        /// </summary>
        private IList<IBoot> _bootConfigs;

        #region Boot

        /// <summary>
        ///     进行启动
        /// </summary>
        public void Boot()
        {
            InitialFrame();

            LoadBootInstance();

            CheckRepeat();

            BootEach();
        }

        private void InitialFrame()
        {
            BaseException.InitialException();
        }

        private void LoadBootInstance()
        {
            ObjectFactory.Configure(x =>
            {
                x.Scan(p =>
                {
                    p.AssembliesFromApplicationBaseDirectory();
                    p.AddAllTypesOf<IBoot>();
                });
                x.For<IBoot>().Singleton();
            });
            _bootConfigs = ObjectFactory.GetAllInstances<IBoot>();
        }

        void CheckRepeat()
        {
            foreach (var boot in _bootConfigs)
            {
                if (_bootConfigs.Count(b => b.Name == boot.Name) > 1)
                {
                    throw new FrameExcetpion("FB2", new string[] { boot.Name });
                }
            }
        }

        void BootEach()
        {
            if (_bootConfigs != null)
            {
                while (_bootConfigs.Count > 0)
                {
                    //找到下一个可以启动的内容
                    IBoot boot =
                        _bootConfigs.Where(b => b.PreBootList == null || b.PreBootList.Count == 0).FirstOrDefault();
                    //如果未找到下一个可以启动的内容
                    if (boot == null)
                    {
                        throw new FrameExcetpion("FB1");
                    }
                    //进行启动
                    boot.Boot();
                    //移除该启动项
                    _bootConfigs.Remove(boot);
                    //移除剩余启动项对该启动项的前置约束
                    foreach (IBoot config in _bootConfigs)
                    {
                        if (config.PreBootList != null
                            && config.PreBootList.Contains(boot.Name))
                        {
                            config.PreBootList.Remove(boot.Name);
                        }
                    }
                }
            }
        }

        #endregion
    }
}
